#include <vector>
#include <fstream>
#include <assert.h>
#include <stdlib.h>
#include <algorithm>
#include <stdio.h>
#include <errno.h>
#include <set>


#include "memalloc.hpp"
#include "memalloc_templ.hpp"
#include "memalloc.h"

//std::vector<uint64_t> ids_;
/*
std::set<uint64_t> ids_; //LESHCH возможно unordered_set будет быстрее при _очень большом_ кол-ве id-шников
std::atomic_flag ids_lock = ATOMIC_FLAG_INIT;
*/
int ma_init(uint64_t mem, uint64_t swap, const char* swap_path) {
	try {
		MemAlloc::Init(mem, swap, swap_path);
//		ids_.clear();
//		std::atomic_flag_clear(&ids_lock);
		return 1;
	}
	catch (MemAllocException& e) {
		fprintf(stderr, "%s\n", e.what());
		errno = e.GetErrorCode();
	}
	catch (std::bad_alloc& e) {
		fprintf(stderr, "%s\n", e.what());
		errno = ENOMEM;
	}
	catch (std::ios_base::failure& e) {
		fprintf(stderr, "%s\n", e.what());
		errno = EACCES;
	}
	catch (...) {
		fprintf(stderr, "Unknown std::exception\n");
	}
	return 0;
}

void ma_deinit() {
	try {
		MemAlloc::Deinit();
//		while (ids_lock.test_and_set())
//			;
//		for (auto i : ids_) {
//			delete (SmartPtr<char>*)i;
//		}
//		ids_.clear();
//		ids_lock.clear();
	}
	catch (std::exception& e) {
		fprintf(stderr, "%s\n", e.what());
		//exit(-1);
	}
	catch (...) {
		fprintf(stderr, "Unknown std::exception\n");
		// exit(-1);
	}

}

uint64_t ma_alloc(uint64_t sz) {
	try {
		SmartPtr<char> sp = MemAlloc::Instance().Alloc<char>(sz);
		SmartPtr<char> *sp_id = new SmartPtr<char>(sp);
//		uint64_t id = (uint64_t)sp_id;
//		//assert(std::find(ids_.begin(), ids_.end(), id) == ids_.end());
//		while (ids_lock.test_and_set())
//			;
//		ids_.push_back((uint64_t)sp_id);
//		ids_lock.clear();
		return (uint64_t)sp_id;
	}
	catch (MemAllocException& e) {
		fprintf(stderr, "%s\n", e.what());
		MemAllocException::ErrorCode code = e.GetErrorCode();
		if (code == MemAllocException::E_NOMEM) //LESHCH выше этот момент был сделан правильнее
			errno = ENOMEM;
		else if (code == MemAllocException::E_2BIG)
			errno = E2BIG;
		else if (code == MemAllocException::E_MLINK)
			errno = EMLINK;
		else if (code == MemAllocException::E_UNINITIALIZED)//!!!added
			errno = ECANCELED;
		//else
		//        exit(-1);
		return 0;
	}
	catch (std::exception& e) {
		fprintf(stderr, "%s\n", e.what());
		return 0;
	}
	catch (...) {
		fprintf(stderr, "Unknown std::exception\n");
		return 0;
	}
}

int ma_free(uint64_t id) {
	try {
//		while (ids_lock.test_and_set())
//			;
//		if (!ids_.count(id)) {
//			errno = EFAULT;
//			ids_lock.clear();
//			return 0;
//		}
//		ids_.erase(id);
//		ids_lock.clear();
		SmartPtr<char> *sp_id = (SmartPtr<char>*) id;
		MemAlloc::Instance().Free(*sp_id);
		delete sp_id;
		return 1;
	}
	catch (std::exception& e) {
		fprintf(stderr, "%s\n", e.what());
	}
	catch (...) {
		fprintf(stderr, "Unknown std::exception\n");
	}
//	ids_lock.clear();
	return 0;
}

void* ma_get(uint64_t id) {
	try {
//		while (ids_lock.test_and_set())
//			;
//		if (!ids_.count(id)) {
//			errno = EFAULT;
//			ids_lock.clear();
//			return 0;
//		}
//		ids_lock.clear(); //LESHCH до следующей инструкции другой поток может успеть, например, сделать free этому id-шнику
		SmartPtr<char> *sp_id = (SmartPtr<char>*) id;
		return sp_id->Get();
	}
	catch (MemAllocException& e) {
		fprintf(stderr, "%s\n", e.what());
		MemAllocException::ErrorCode code = e.GetErrorCode();
		if (code == MemAllocException::E_NOMEM)
			errno = ENOMEM;
		else if (code == MemAllocException::E_NOBUFS)
			errno = ENOBUFS;
	}
	catch (std::ios_base::failure& e) {
		fprintf(stderr, "%s\n", e.what());
		errno = EBADF;
	}
	catch (std::exception& e) {
		fprintf(stderr, "%s\n", e.what());
	}
	catch (...) {
		fprintf(stderr, "Unknown std::exception\n");
	}
	return 0;
}

int ma_release(uint64_t id) {
	try {
//		while (ids_lock.test_and_set())
//			;
//		if (!ids_.count(id)) {
//			errno = EFAULT;
//			ids_lock.clear();
//			return 0;
//		}
//		ids_lock.clear();
		SmartPtr<char> *sp_id = (SmartPtr<char>*) id;
		sp_id->Release();
		return 1;
	}
	catch (std::exception& e) {
		fprintf(stderr, "%s\n", e.what());
		//    exit(-1);
	}
	catch (...) {
		fprintf(stderr, "Unknown std::exception\n");
		//   exit(-1);
	}
	return 0;
}

